/*
 * @(#)FormDataToXml.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.form.core;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;

import com.dcivision.form.bean.FormData;
import com.dcivision.form.bean.FormDataElement;
import com.dcivision.form.bean.FormElement;
import com.dcivision.form.bean.FormPage;
import com.dcivision.form.bean.FormRecord;
import com.dcivision.form.bean.FormSection;
import com.dcivision.form.dao.FormDataElementDAObject;
import com.dcivision.form.dao.FormElementDAObject;
import com.dcivision.form.dao.FormPageDAObject;
import com.dcivision.form.dao.FormRecordDAObject;
import com.dcivision.form.dao.FormSectionDAObject;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.Utility;

/**
 * FormDataToXml.java
 * 
 * This class is responsible for formdata convert to xml operation.
 * 
 * @author Charlie Liu
 * @company DCIVision Limited
 * @creation date 21/12/2005
 * @version $Revision: 1.4 $
 */
public class FormDataToXml {

	private static final String XML_ELEMENT_LEVEL1 = "para-form";
	private static final String XML_ELEMENT_LEVEL1_ATTR1 = "id";
	private static final String XML_ELEMENT_LEVEL1_ATTR2 = "title";

	private static final String XML_ELEMENT_LEVEL2 = "page";
	private static final String XML_ELEMENT_LEVEL2_ATTR1 = "id";
	private static final String XML_ELEMENT_LEVEL2_ATTR2 = "title";
	private static final String XML_ELEMENT_LEVEL2_ATTR3 = "page_num";

	private static final String XML_ELEMENT_LEVEL3 = "section";
	private static final String XML_ELEMENT_LEVEL3_ATTR1 = "id";
	private static final String XML_ELEMENT_LEVEL3_ATTR2 = "title";
	private static final String XML_ELEMENT_LEVEL3_ATTR3 = "sequ";

	private static final String XML_ELEMENT_LEVEL4 = "element";
	private static final String XML_ELEMENT_LEVEL4_ATTR1 = "id";
	private static final String XML_ELEMENT_LEVEL4_ATTR2 = "name";
	private static final String XML_ELEMENT_LEVEL4_ATTR3 = "sequ";
	
	protected Log log = LogFactory.getLog(this.getClass().getName());
	private SessionContainer sessionCon = null;
	private Connection dbConn = null;
	private Document doc;

	/**
	 * Constructor
	 * 
	 * @param sessionContainer
	 * @param conn
	 */
	public FormDataToXml(SessionContainer sessionContainer, Connection conn) {
		this.sessionCon = sessionContainer;
		this.dbConn = conn;
	}

	private FormDataToXml() {

	}

	public Document process(List formdatas) {

		if (formdatas == null || formdatas.size() < 1) {
			return null;
		}
		FormDataElementDAObject formDataElementDAObject = new FormDataElementDAObject(sessionCon, dbConn);
		FormRecordDAObject formRecordDAObject = new FormRecordDAObject(sessionCon,dbConn);
		FormPageDAObject formPageDAObject = new FormPageDAObject(sessionCon, dbConn);
		FormSectionDAObject formSectionDAObject = new FormSectionDAObject(sessionCon, dbConn);
		FormElementDAObject formElementDAObject = new FormElementDAObject(sessionCon, dbConn);
		boolean hasDoc = false;	
		
		for (int i = 0; i < formdatas.size(); i++) {
			FormData formData = (FormData) formdatas.get(i);
			if (formData == null || Utility.isEmpty(formData.getID())
					|| Utility.isEmpty(formData.getDataElementID())
					|| (formData.getDataString() == null &&
					    formData.getDataObject() == null)){
				continue;
			}
			try {
				FormDataElement formDataElement = (FormDataElement) formDataElementDAObject
						.getObjectByID(formData.getDataElementID());
				FormPage formPage = (FormPage) formPageDAObject
						.getObjectByID(formDataElement.getPageID());
				FormSection formSection = (FormSection) formSectionDAObject
						.getObjectByID(formDataElement.getSectionID());
				FormElement formElement = (FormElement) formElementDAObject
						.getObjectByID(formDataElement.getElementID());

				if (!hasDoc) {
					FormRecord formRecord = (FormRecord) formRecordDAObject
							.getObjectByID(formPage.getFormRecordID());
					if (this.addFormInf(formRecord) != null) {
						hasDoc = true;
					}
				}
				this.addElement(formPage, formSection, formElement, formData);
			} catch (Exception e) {
				log.error("Get data from db error! " + e);
			}
		}
		try{
			this.formatOut(this.doc);
		}catch(Exception e){
			
		}		
		return this.doc;
	}

	private Element addFormInf(FormRecord formRecord) {
		if (formRecord == null || Utility.isEmpty(formRecord.getID())
				|| Utility.isEmpty(formRecord.getTitle())) {
			return null;
		}
		if (this.doc == null) {
			this.doc = this.createBlankDoc();
		}
		Element root = this.doc.getRootElement();
		root.setAttribute(this.XML_ELEMENT_LEVEL1_ATTR1, formRecord.getID()
				.toString());
		root.setAttribute(this.XML_ELEMENT_LEVEL1_ATTR2, formRecord.getTitle());
		return root;
	}

	private Document createBlankDoc() {
		Document doc = new Document();
		Element para_form = new Element(this.XML_ELEMENT_LEVEL1);
		para_form.setAttribute(this.XML_ELEMENT_LEVEL1_ATTR1, "");
		para_form.setAttribute(this.XML_ELEMENT_LEVEL1_ATTR2, "");
		doc.setRootElement(para_form);
		return doc;
	}
	
	private Element addPage(FormPage formPage) throws JDOMException {

		log.debug("addPage Start!");
		if (formPage == null || Utility.isEmpty(formPage.getID())
				|| Utility.isEmpty(formPage.getTitle())) {
			log.debug("formPage is error!");
			return null;
		}
		if (this.doc == null) {
			log.debug("this.doc is null!");
			return null;
		}
		String basePath = "/" + this.XML_ELEMENT_LEVEL1;
		XPath xpath = XPath.newInstance(basePath + "/" + this.XML_ELEMENT_LEVEL2
				+ "[@" + this.XML_ELEMENT_LEVEL2_ATTR1 + "=\""
				+ formPage.getID().toString() + "\"]");
		log.debug("pagePath=" + xpath.toString());
		Element page = (Element) xpath.selectSingleNode(this.doc);
		if (page == null) {
			Element root = this.doc.getRootElement();
			page = new Element(this.XML_ELEMENT_LEVEL2);
			page.setAttribute(this.XML_ELEMENT_LEVEL2_ATTR1, formPage.getID()
					.toString());
			page.setAttribute(this.XML_ELEMENT_LEVEL2_ATTR2, formPage.getTitle());
			page.setAttribute(this.XML_ELEMENT_LEVEL2_ATTR3, formPage.getPageNo()
					.toString());
			root.addContent(page);
		}
		log.debug("addPage End!");
		return page;
	}

	private Element addSection(FormPage formPage, FormSection formSection) throws JDOMException {

		log.debug("addSection Start!");
		if (formSection == null || Utility.isEmpty(formSection.getID())
				|| Utility.isEmpty(formSection.getTitle())) {
			log.debug("formSection is error!");
			return null;
		}
		if (this.doc == null) {
			log.debug("this.doc is null!");
			return null;
		}
		Element page = this.addPage(formPage);
		if (page == null) {
			log.debug("addPage error!");
			return null;
		}			
		String basePath = "/" + this.XML_ELEMENT_LEVEL1 + "/"
				+ this.XML_ELEMENT_LEVEL2;
		XPath sectionPath = XPath.newInstance( this.XML_ELEMENT_LEVEL3 + "[@" + this.XML_ELEMENT_LEVEL3_ATTR1
				+ "=\"" + formSection.getID().toString() + "\"]");

		log.debug("sectionPath:" + sectionPath.getXPath());
		Element section = (Element) sectionPath.selectSingleNode(page);
		if (section == null) {
			log.debug("section is null!then add the section!");
			section = new Element(this.XML_ELEMENT_LEVEL3);
			section.setAttribute(this.XML_ELEMENT_LEVEL3_ATTR1, formSection.getID()
					.toString());
			section.setAttribute(this.XML_ELEMENT_LEVEL3_ATTR2, formSection
					.getTitle());
			// section.setAttribute(this.XML_ELEMENT_LEVEL3_ATTR3, sequ);
			page.addContent(section);
		}
		log.debug("addSection End!");
		return section;
	}

	private Element addElement(FormPage formPage, FormSection formSection,
			FormElement formElement, FormData formData)
			throws JDOMException {

		log.debug("addElement Start!");
		if (formElement == null || Utility.isEmpty(formElement.getID())
				|| formElement.getFieldName() == null) {
			log.debug("formElement is error!");
			return null;
		}
		if (doc == null) {
			log.debug("this.doc is null!");
			return null;
		}		
		Element section = this.addSection(formPage, formSection);
		if (section == null) {
			log.debug("addSection error!");
			return null;
		}
		XPath elementPath = XPath.newInstance(this.XML_ELEMENT_LEVEL4 + "[@" + this.XML_ELEMENT_LEVEL4_ATTR1
				+ "=\"" + formElement.getID().toString() + "\"]");		
		log.debug("elementPaht:" + elementPath.getXPath());
		Element element = (Element) elementPath.selectSingleNode(section);
		if (element == null) {
			log.debug("element is null!then add this element!");
			element = new Element(this.XML_ELEMENT_LEVEL4);
			element.setAttribute(this.XML_ELEMENT_LEVEL4_ATTR1, formElement.getID()
					.toString());
			element.setAttribute(this.XML_ELEMENT_LEVEL4_ATTR2, formElement
					.getFieldName());
			// element.setAttribute(this.XML_ELEMENT_LEVEL4_ATTR3, element_seq);
			if(formData.getDataObject()==null){
				element.addContent(formData.getDataString());
			}else{
				element.addContent(formData.getDataObject().toString());
			}			
			section.addContent(element);
		}else{
			String newValue ="";
			if(formData.getDataObject()!=null){				
				newValue=formData.getDataObject().toString();
			}else{
				if(formData.getDataString()!=null)					
				newValue=formData.getDataString();
			}			
			element.addContent(" "+newValue);
		}
		log.debug("addElement End!");
		return element;
	}

	private void formatOut(Document doc) throws IOException, FileNotFoundException {

		Format format = Format.getCompactFormat();
		format.setEncoding("UTF-8");
		format.setIndent("  ");
		XMLOutputter XMLOut = new XMLOutputter(format);
		XMLOut.output(doc, new FileOutputStream("f:/formData.xml"));
	}

	public static void main(String args[]) throws Exception {

		System.out.println("Now we build an XML document .....");
		FormDataToXml formDataToXml = new FormDataToXml();

		FormRecord formRecord = new FormRecord();
		formRecord.setID(new Integer(100));
		formRecord.setTitle("TestForm1");

		FormPage formPage1 = new FormPage();
		formPage1.setID(new Integer(1000));
		formPage1.setTitle("Page1");
		formPage1.setPageNo(new Integer(1));

		FormPage formPage2 = new FormPage();
		formPage2.setID(new Integer(1001));
		formPage2.setTitle("Page2");
		formPage2.setPageNo(new Integer(2));

		FormSection formSection1 = new FormSection();
		formSection1.setID(new Integer(10000));
		formSection1.setTitle("Section1");

		FormSection formSection2 = new FormSection();
		formSection2.setID(new Integer(10001));
		formSection2.setTitle("Section2");

		FormElement formElement1 = new FormElement();
		formElement1.setID(new Integer(100000));
		formElement1.setFieldName("Element1");

		FormElement formElement2 = new FormElement();
		formElement2.setID(new Integer(100001));
		formElement2.setFieldName("Element2");
		
		FormData formData = new FormData();
		formData.setDataString("ABC");

		formDataToXml.addFormInf(formRecord);

		formDataToXml.addElement(formPage1, formSection1, formElement1, formData);
		formDataToXml.addElement(formPage1, formSection1, formElement1, formData);
		formDataToXml.addElement(formPage1, formSection1, formElement2, formData);
		formDataToXml.addElement(formPage1, formSection2, formElement1, formData);
		formDataToXml.addElement(formPage1, formSection2, formElement2, formData);
		formDataToXml.addElement(formPage2, formSection1, formElement1, formData);
		formDataToXml.addElement(formPage2, formSection1, formElement2, formData);
		formDataToXml.addElement(formPage2, formSection2, formElement1, formData);
		formDataToXml.addElement(formPage2, formSection2, formElement2, formData);

		formDataToXml.formatOut(formDataToXml.doc);

		System.out.println("finished!");
	}

}
